﻿using System;
using System.Text;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
using Microsoft.VisualBasic;
using System.Reflection;

namespace WinnerCMS.Common.Userdefined
{
    /// <summary>
    /// 自定义公式
    /// </summary>
    /// <remarks>调用例子 double a = (double)Evaluator.Eval("sin(0.2) + 5");</remarks>
    public class Evaluator
    {
        #region 执行公式
        /// <summary>
        /// 执行公式
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public static object Eval(string expression)
        {
            CSharpCodeProvider provider = new CSharpCodeProvider();
            CompilerParameters parameter = new CompilerParameters();
            parameter.ReferencedAssemblies.Add("System.dll");
            parameter.GenerateExecutable = false;
            parameter.GenerateInMemory = true;

            StringBuilder codeBuilder = new StringBuilder();

            codeBuilder.AppendLine("using System;");
            codeBuilder.AppendLine("namespace WinnerCMS.Common.AutoApp{");
            codeBuilder.AppendLine("public static class Mode" +
                                   "{");
            codeBuilder.AppendLine("   public static object Func()" +
                                   "    {");
            codeBuilder.AppendLine("        return " + expression + ";");
            codeBuilder.AppendLine("    }");
            codeBuilder.AppendLine("}}");

            CompilerResults result = provider.CompileAssemblyFromSource(parameter, codeBuilder.ToString());
            if (result.Errors.Count > 0)
            {
                throw new NotImplementedException("动态编译出错了！");
            }
            else
            {
                Assembly assembly = result.CompiledAssembly;
                Type mode = assembly.GetType("WinnerCMS.Common.Mode");
                MethodInfo method = mode.GetMethod("Func");
                return method.Invoke(null, null);
            }
        }
        #endregion

        #region 执行公式
        /// <summary>
        /// 执行公式
        /// </summary>
        /// <param name="expression">公式</param>
        /// <returns></returns>
        /// <remarks>调用例子 double a = (double)Evaluator.Eval("sin(0.2) + 5");</remarks>
        public static object EvalVB(string expression)
        {
            CodeDomProvider comp = new VBCodeProvider();
            CompilerParameters cp = new CompilerParameters();
            StringBuilder codeBuilder = new StringBuilder();

            codeBuilder.AppendLine("Imports System");
            codeBuilder.AppendLine("Imports System.Math");
            codeBuilder.AppendLine("Imports Microsoft.VisualBasic");
            codeBuilder.AppendLine();
            codeBuilder.AppendLine("Public Module Mode");
            codeBuilder.AppendLine("   Public Function Func() As Object");
            codeBuilder.AppendLine("        Return " + expression);
            codeBuilder.AppendLine("   End Function");
            codeBuilder.AppendLine("End Module");

            cp.ReferencedAssemblies.Add("System.dll");
            cp.ReferencedAssemblies.Add("Microsoft.VisualBasic.dll");
            cp.GenerateExecutable = false;
            cp.GenerateInMemory = true;

            string code = codeBuilder.ToString();
            CompilerResults cr = comp.CompileAssemblyFromSource(cp, code);

            if (cr.Errors.HasErrors)
            {
                return null;
            }
            else
            {
                Assembly a = cr.CompiledAssembly;
                Type t = a.GetType("Mode");

                MethodInfo mi = t.GetMethod("Func", BindingFlags.Static | BindingFlags.Public);


                return mi.Invoke(null, new object[0]);
            }
        }
        #endregion
    }
}

